package com.zusmart.core.bean.support;

import com.zusmart.base.util.Assert;
import com.zusmart.base.util.StringUtils;
import com.zusmart.core.bean.BeanDefinition;
import com.zusmart.core.bean.BeanDefinitionRegistry;
import com.zusmart.core.bean.BeanDefinitionResolver;
import com.zusmart.core.bean.BeanDefinitionType;
import com.zusmart.core.bean.BeanInstanceCreator;
import com.zusmart.core.bean.BeanInstanceHandler;
import com.zusmart.core.bean.cause.BeanInstanceCreateException;
import com.zusmart.core.bean.cause.BeanInstanceDestoryException;
import com.zusmart.core.bean.cause.BeanInstanceInitialException;
import com.zusmart.core.bean.cause.BeanInstanceInjectException;
import com.zusmart.core.bean.cause.BeanInstanceNotFoundException;
import com.zusmart.core.bean.cause.BeanInstanceReleaseException;

public abstract class AbstractBeanDefinition implements BeanDefinition {

	private final BeanDefinitionResolver beanDefinitionResolver;
	private final BeanDefinitionRegistry beanDefinitionRegistry;

	private final BeanInstanceCreator beanInstanceCreator;
	private final BeanInstanceHandler beanInstanceHandler;

	private String beanName;
	private String beanScope;
	private Class<?> beanClass;

	protected AbstractBeanDefinition(BeanDefinitionResolver beanDefinitionResolver, BeanDefinitionRegistry beanDefinitionRegistry, String beanName, String beanScope, Class<?> beanClass) {
		Assert.isNull(beanDefinitionResolver, "bean definition resovler must not be null");
		Assert.isNull(beanDefinitionRegistry, "bean definition registry must not be null");
		Assert.isBlank(beanName, "bean name must not be blank");
		Assert.isNull(beanClass, "bean class must not be null");
		this.beanDefinitionResolver = beanDefinitionResolver;
		this.beanDefinitionRegistry = beanDefinitionRegistry;
		this.beanName = beanName;
		this.beanScope = StringUtils.isBlank(beanScope) ? SCOPE_SINGLETON : beanScope.toLowerCase();
		this.beanClass = beanClass;

		this.beanInstanceCreator = this.createBeanInstanceCreator();
		this.beanInstanceHandler = this.createBeanInstanceHandler();

	}

	@Override
	public void doCreate() throws BeanInstanceCreateException {
		this.beanInstanceHandler.doCreate();
	}

	@Override
	public void doInject() throws BeanInstanceInjectException {
		this.beanInstanceHandler.doInject();
	}

	@Override
	public void doInitial() throws BeanInstanceInitialException {
		this.beanInstanceHandler.doInitial();
	}

	@Override
	public void doRelease() throws BeanInstanceReleaseException {
		this.beanInstanceHandler.doRelease();
	}

	@Override
	public void doDestory() throws BeanInstanceDestoryException {
		this.beanInstanceHandler.doDestory();
	}

	@Override
	public String getBeanName() {
		return this.beanName;
	}

	@Override
	public String getBeanScope() {
		return this.beanScope;
	}

	@Override
	public Class<?> getBeanClass() {
		return this.beanClass;
	}

	@Override
	public Object getBeanInstance() throws BeanInstanceNotFoundException {
		try {
			return this.beanInstanceHandler.getBeanInstance();
		} catch (BeanInstanceCreateException e) {
			throw new BeanInstanceNotFoundException(e.getMessage());
		}
	}

	@Override
	public boolean isSingleton() {
		return SCOPE_SINGLETON.equals(this.beanScope);
	}

	@Override
	public boolean isPrototype() {
		return SCOPE_PROTOTYPE.equals(this.beanScope);
	}

	@Override
	public boolean isClassType() {
		return this.getBeanType() == BeanDefinitionType.Class;
	}

	@Override
	public boolean isMethodType() {
		return this.getBeanType() == BeanDefinitionType.Method;
	}

	@Override
	public boolean isObjectType() {
		return this.getBeanType() == BeanDefinitionType.Object;
	}

	@Override
	public boolean isAssignable(Class<?> beanType) {
		if (null == beanType) {
			return false;
		}
		return beanType.isAssignableFrom(this.beanClass);
	}

	@Override
	public BeanInstanceHandler getBeanInstanceHandler() {
		return this.beanInstanceHandler;
	}

	@Override
	public BeanInstanceCreator getBeanInstanceCreator() {
		return this.beanInstanceCreator;
	}

	@Override
	public BeanDefinitionResolver getBeanDefinitionResolver() {
		return this.beanDefinitionResolver;
	}

	@Override
	public BeanDefinitionRegistry getBeanDefinitionRegistry() {
		return this.beanDefinitionRegistry;
	}

	@Override
	public String toString() {
		StringBuffer sb = new StringBuffer();
		sb.append("[").append(this.beanScope).append("]");
		sb.append(this.beanClass.getName()).append("#").append(this.beanName);
		return sb.toString();
	}

	protected BeanInstanceHandler createBeanInstanceHandler() {
		if (this.isSingleton()) {
			return new BeanInstanceHandlerForSingleton(this);
		} else {
			return new BeanInstanceHandlerForPrototype(this);
		}
	}

	protected abstract BeanInstanceCreator createBeanInstanceCreator();

}